﻿/*
* ----------------------------------------
*  ScrollBar Class
* 
*  Author 	: iCoo ( Lee Chang-Min )
*  Contact	: www.i-coo.co.kr
*  E-mail	: icoo0211@gmail.com
*  Update   : 2010. 07. 05
* ----------------------------------------
* 
*  addChild( new Scroller( new Contents(), new Point( 400, 400 ) ));
* 
*  addChild( new Scroller( new Contents(), new Point( 400, 400 ), { scrollPos: "right", isButton: true, isWheel: true, isBgClick: true, isScrollOver: true } ));
* 
* 1. 라이브러리에 심볼이 있어야 한다.
* 2. 스크롤 될 컨텐츠와 사이즈는 반드시 작성해야한다.
*/

package com.coo.display 
{
	import com.greensock.easing.Cubic;
	import com.greensock.TweenLite;
	import flash.display.*;
	import flash.events.*;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	
	public class Scroller extends Sprite
	{
		private var _content: DisplayObject;
		private var _mask: Shape;
		
		private var _scrollBar: MovieClip;
		private var _bar: MovieClip;
		private var _bg: MovieClip;
		private var _upBtn: MovieClip;
		private var _downBtn: MovieClip;
		
		private var _maskSize: Point;
		private var _attributes: Object;
		
		private var _maskHtMin: int = 400;
		private var _scrollMin: int;
		private var _scrollMax: int;
		private var _max: int;
		private var _min: int;
		private var _btnBoundary: uint = 30;
		private var _wheelBoundary: uint = 40;
		
		public function Scroller( content: DisplayObject, size: Point, attributes: Object = null )
		{
			_content = content;
			_maskSize = size;
			_attributes = attributes;
			
			for( var value: * in attributes )
			{
				_attributes[ value ] = attributes[ value ];
			}
			
			init();
		}
		
		private function init(): void
		{
			setChildren();
		}
		
		private function setChildren(): void
		{
			
			// ::::::::::::::::::::::::::::::  set content  ::::::::::::::::::::::::::::::  
			addChildAt( _content, 0 );
			
			if ( _maskSize.y > _content.height ) return;
			
			
			// ::::::::::::::::::::::::::::::  set mask  ::::::::::::::::::::::::::::::  
			_mask = new Shape();
			_mask.graphics.beginFill( 0x0 );
			_mask.graphics.drawRect( 0, 0, _maskSize.x, _maskSize.y );
			
			addChildAt( _mask, 1 );
			_content.mask = _mask;
			
			
			// ::::::::::::::::::::::::::::::  set scroll bar  ::::::::::::::::::::::::::::::  
			_scrollBar = this.getChildByName( "scrollBar" ) as MovieClip;
			_bar = _scrollBar.getChildByName( "bar" ) as MovieClip;
			_bg = _scrollBar.getChildByName( "bg" ) as MovieClip;
			
			_bar.buttonMode = true;
			
			if ( _attributes.scrollPos == "left" )
			{
				_scrollBar.x = 0;
				_content.x = _bg.width;
			} else
			{
				_scrollBar.x = _maskSize.x;
			}
			
			if ( _attributes.isButton )
			{
				_scrollBar.addChild( _upBtn = new UpBtn());
				_scrollBar.addChild( _downBtn = new DownBtn());
				_upBtn.name = "up";
				_upBtn.buttonMode = true;
				_downBtn.name = "down";
				_downBtn.buttonMode = true;
				
				_downBtn.y = _maskSize.y - _downBtn.height;
				
				_bg.y = _upBtn.height;
				_bg.height = _maskSize.y - _upBtn.height - _downBtn.height;
				
				_bar.y = _bg.y;
				
				_scrollMin = _upBtn.height;
				_scrollMax = _maskSize.y - _upBtn.height - _downBtn.height - _bar.height;
				
			} else
			{
				_bg.height = _maskSize.y;
				
				_scrollMin = 0;
				_scrollMax = _maskSize.y - _bar.height;
			}
			
			if ( _attributes.isScrollOver ) _scrollBar.alpha = 0;
			addChild( _scrollBar );
			
			addEvent();
		}
		
		private function addEvent(): void
		{
			_bar.addEventListener( MouseEvent.MOUSE_DOWN, pressHandler );
			
			if ( _attributes.isButton )
			{
				_upBtn.addEventListener( MouseEvent.CLICK, clickHandler );
				_downBtn.addEventListener( MouseEvent.CLICK, clickHandler );
			}
			
			if ( _attributes.isBgClick ) _bg.addEventListener( MouseEvent.CLICK, clickHandler );
			if ( _attributes.isWheel ) addEventListener( MouseEvent.MOUSE_WHEEL, wheelHandler );
			if ( _attributes.isScrollOver )
			{
				addEventListener( MouseEvent.ROLL_OVER, overHandler );
				addEventListener( MouseEvent.ROLL_OUT, outHandler );
			}
		}
		
		private function overHandler( e: MouseEvent ): void
		{
			TweenLite.to( _scrollBar, 0.3, { alpha: 1 } );
		}
		
		private function outHandler( e: MouseEvent ): void
		{
			TweenLite.to( _scrollBar, 0.3, { alpha: 0 } );
		}
		
		private function pressHandler( e: MouseEvent ): void
		{
			stage.addEventListener( MouseEvent.MOUSE_MOVE, moveHandler );
			
			_bar.startDrag( false, new Rectangle( 0, _scrollMin, 0, _scrollMax ));
			stage.addEventListener( MouseEvent.MOUSE_UP, releaseHandler );
		}
		
		private function releaseHandler( e: MouseEvent ): void
		{
			stage.removeEventListener( MouseEvent.MOUSE_MOVE, moveHandler );
			
			_bar.stopDrag();
			stage.removeEventListener( MouseEvent.MOUSE_UP, releaseHandler );
		}
		
		private function clickHandler( e: MouseEvent ): void
		{
			var mc: MovieClip = e.target as MovieClip;
			
			switch( mc.name )
			{
				case "up" :
				
					if ( _bar.y - _btnBoundary < _scrollMin ) _bar.y = _scrollMin;
					else _bar.y -= _btnBoundary;
					
					activeScroll();
				break;
				
				case "down" :
				
					if ( _bar.y + _btnBoundary > _scrollMax + _scrollMin ) _bar.y = _scrollMax + _scrollMin;
					else _bar.y += _btnBoundary;
					
					activeScroll();
				break;
				
				case "bg" :
					
					var target: int = int( ( mc.parent as MovieClip).mouseY );
					
					if ( target > _scrollMax + _scrollMin ) _bar.y  = _scrollMax + _scrollMin;
					else _bar.y = target;
					
					activeScroll();
				break;
			}
		}
		
		private function wheelHandler( e: MouseEvent ): void
		{
			if ( e.delta > 0 )
			{
				if ( _bar.y - _wheelBoundary < _scrollMin ) _bar.y = _scrollMin;
				else _bar.y -= _wheelBoundary;
				
				activeScroll();
			} else
			{
				if ( _bar.y + _wheelBoundary > _scrollMax + _scrollMin ) _bar.y = _scrollMax + _scrollMin;
				else _bar.y += _wheelBoundary;
				
				activeScroll();
			}
		}
		
		private function moveHandler( e: Event ): void
		{
			activeScroll();
		}
		
		private function activeScroll(): void
		{
			// 비례 공식
			// 스크롤의 최대값 : 바의 위치 - 스크롤 최소값 = 컨텐츠가 움직일 수 있는 최대값 : 컨텐츠 위치
			// _scrollMax  : (_bar.y - _scrollMin) = ( _content.height - _maskSize.y ) : _cont.y;
			// trace( "Scroll per :  " + ((_bar.y-_scrollMin) / (_scrollMax)) * 100);
			
			var pos: int = ( _bar.y - _scrollMin) * ( _content.height - _maskSize.y ) / _scrollMax;
			
			TweenLite.to( _content, 0.3, { y: -pos, ease: Cubic.easeOut } );
		}
		
		// ::::::::::::::::::::::::::::::  public Methods  ::::::::::::::::::::::::::::::  
		
		public function resize( wh: int, ht: int ): void
		{
			if ( ht < _maskHtMin ) return;
			
			var gap: int = ht - _maskSize.y;
			
			_maskSize.x = wh;
			_maskSize.y = ht;
			
			_mask.graphics.clear();
			_mask.graphics.beginFill( 0x0 );
			_mask.graphics.drawRect( 0, 0, _maskSize.x, _maskSize.y );
			
			if ( _attributes.isButton == true )
			{
				_downBtn.y = _maskSize.y - _downBtn.height;
				
				_bg.y = _upBtn.height;
				_bg.height = _maskSize.y - _upBtn.height - _downBtn.height;
				
				_bar.y = _bg.y;
				
				_scrollMin = _upBtn.height;
				_scrollMax = _maskSize.y - _upBtn.height - _downBtn.height - _bar.height;
				
			} else
			{
				_bg.height = _maskSize.y;
				
				_scrollMin = 0;
				_scrollMax = _maskSize.y - _bar.height;
			}
			
			if ( _bar.y > 0 ) _bar.y += gap;
			
			activeScroll();
		}
		
		// ::::::::::::::::::::::::::::::  get/set Methods  ::::::::::::::::::::::::::::::  
		
		public function get btnBoundary(): uint { return _btnBoundary;  }
		public function set btnBoundary( value: uint ): void { _btnBoundary = value; }
		
		public function get wheelBoundary(): uint { return _wheelBoundary;  }
		public function set wheelBoundary( value: uint ): void { _wheelBoundary = value; }
		
		public function get maskHtMin(): uint { return _maskHtMin;  }
		public function set maskHtMin( value: uint ): void { _maskHtMin = value; }
		
		public function get bar(): MovieClip { return _bar; }
	}
}